package com.example.demo.utils.webSocketUtils

import com.example.demo.dao.TBoardMessageDao
import com.example.demo.dao.TDeviceDao
import com.example.demo.dao.Tables.tDevices
import com.example.demo.utils.LogUtils
import com.example.demo.utils.WebDatabase
import com.google.gson.Gson
import me.liuwj.ktorm.dsl.eq
import me.liuwj.ktorm.dsl.insertAndGenerateKey
import me.liuwj.ktorm.dsl.update
import me.liuwj.ktorm.entity.filter
import me.liuwj.ktorm.entity.firstOrNull
import org.apache.commons.beanutils.BeanUtils
import org.apache.commons.lang3.time.DateFormatUtils
import org.springframework.stereotype.Component
import org.springframework.util.StringUtils
import java.util.*
import java.util.concurrent.ConcurrentMap
import javax.websocket.OnClose
import javax.websocket.OnMessage
import javax.websocket.OnOpen
import javax.websocket.Session
import javax.websocket.server.ServerEndpoint

@Component
@ServerEndpoint("/websocket")
class WebSocketServer {

    val REGISTER = "register"
    val HEART = "heart"
    val REGISTER_RESPONSE = "register_response"
    val RESPONSE_SUCCEED = 1 //1成功
    val RESPONSE_FAILURE = 2 //2失败

    val CALL = "call"
    val CALL_RESPONSE = "call_response"
    val INCALL = "incall"
    val INCALL_RESPONSE = "incall_response"
    val OFFER = "offer"
    val CANDIDATE = "candidate"
    val HANGUP = "hangup"
    val OXMDATA = "oxmdata"
    val FOODORDER = "foodorder"
    val PRODUCTORDER = "productorder"

    private var session: Session? = null
    val webDatabase = WebDatabase()


    /**
     * 连接建立后触发的方法
     */
    @OnOpen
    fun onOpen(session: Session) {
        try {
            this.session = session
            println("onOpen" + session.id)
            WebSocketMapUtil.put(session.id, this)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 连接关闭后触发的方法
     */
    @OnClose
    fun onClose() {
        //从map中删除
        try {
            session?.id?.let { WebSocketMapUtil.remove(it) }
            val entries: ConcurrentMap<String, String> = ClientMapUtil.webSocketMap
            if (entries.size != 0) {
                entries.forEach { entrie ->
                    session?.id?.let { id ->
                        if (StringUtils.pathEquals(id, entrie.value)) {
                            // 再数据库中更新在线状态 1 未在线
                            webDatabase.getDataBase().update(TDeviceDao) {
                                set(it.connect_start, 1)
                                where {
                                    it.device_no eq entrie.key
                                }
                            }
                            entries.remove(entrie)
                            println("====== onClose:" + session?.id + " ====== ${entrie.key}  =====")
                        }
                    }
                }
            }

        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 接收到客户端消息时触发的方法
     */
    @OnMessage
    fun onMessage(params: String, session: Session) {
        LogUtils.e("收到来自" + session.id + "的消息" + params)
        if (!StringUtils.isEmpty(params)) {
            val modelBean: ModelBean = Gson().fromJson<ModelBean>(params, ModelBean::class.java)
            try {
                modelBean.apply {
                    val id: String? = this.id
                    id.let {
                        //获取服务端到客户端的通道
                        val myWebSocket = WebSocketMapUtil[session.id]
                        when (it) {
                            HEART -> { // 心跳包

                            }
                            REGISTER -> { // 注册
                                myWebSocket?.let {
                                    register(it, modelBean)
                                }
                            }
                            CALL -> {  // 请求呼叫视频
                                myWebSocket?.let {
                                    call(myWebSocket, modelBean)
                                }
                            }
                            INCALL_RESPONSE -> {
                                val isSuccees = modelBean.isSucceed
                                if (isSuccees == RESPONSE_FAILURE) {
                                    // 拒接接听
                                    myWebSocket?.let {
                                        incallResponseFailure(myWebSocket, modelBean)
                                    }
                                } else if (isSuccees == RESPONSE_SUCCEED) {
                                    // 同意接听
                                    myWebSocket?.let {
                                        incallResponseSucceed(myWebSocket, modelBean)
                                    }
                                }
                            }
                            OFFER -> {
                                offer(modelBean)
                            }
                            CANDIDATE -> {
                                candidate(modelBean)
                            }
                            HANGUP -> {
                                hangUp(modelBean)
                            }
                            OXMDATA -> {
                                senOxmData(myWebSocket, modelBean)
                            }
                            FOODORDER -> {
                                senFoodOrderData(myWebSocket, modelBean)
                            }
                            PRODUCTORDER -> {
                                senProductOrderData(myWebSocket, modelBean)
                            }
                        }
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    private fun sendMessage(message: ModelBean) {
        try {
            session?.basicRemote?.sendText(Gson().toJson(message))
            LogUtils.e(" 发送信息  ===  ${Gson().toJson(message)}")
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 注册
     *
     * @param myWebSocket
     * @param modelBean
     */
    private fun register(myWebSocket: WebSocketServer, model: ModelBean) {
        try {
            LogUtils.e(Gson().toJson(model))
            val test = ModelBean()
            test.isSucceed = RESPONSE_FAILURE
            test.message = "deviceNo不可为空"

            model.deviceData?.device_no?.let { deviceNo ->
                webDatabase.getDataBase().tDevices.filter {
                    it.device_no eq deviceNo
                }.firstOrNull()?.let {  // 更新数据
                    model.deviceData?.let { deviceVo ->
                        webDatabase.getDataBase().update(TDeviceDao) {
                            set(it.dept_code, deviceVo.dept_code)
                            set(it.dept_name, deviceVo.dept_name)
                            set(it.app_version, deviceVo.app_version)
                            set(it.bed_code, deviceVo.bed_code)
                            set(it.bed_name, deviceVo.bed_name)
                            set(it.device_ip, deviceVo.device_ip)
                            set(it.device_mac, deviceVo.device_mac)
                            set(it.device_type, deviceVo.device_type)
                            set(it.device_no, deviceVo.device_no)
                            set(it.nurseboard_ip, deviceVo.nurseboard_ip)
                            set(it.connect_start, 0)
                            where {
                                it.device_no eq deviceNo
                            }
                        }
                        ClientMapUtil.webSocketMap[deviceNo] = myWebSocket.session?.id
                        test.message = "更新数据成功"
                        test.isSucceed = RESPONSE_SUCCEED
                    }
                } ?: let {   // 添加数据
                    model.deviceData?.let { deviceVo ->
                        webDatabase.getDataBase().insertAndGenerateKey(TDeviceDao) {
                            set(it.dept_code, deviceVo.dept_code)
                            set(it.dept_name, deviceVo.dept_name)
                            set(it.app_version, deviceVo.app_version)
                            set(it.bed_code, deviceVo.bed_code)
                            set(it.bed_name, deviceVo.bed_name)
                            set(it.device_ip, deviceVo.device_ip)
                            set(it.device_mac, deviceVo.device_mac)
                            set(it.device_type, deviceVo.device_type)
                            set(it.device_no, deviceVo.device_no)
                            set(it.nurseboard_ip, deviceVo.nurseboard_ip)
                            set(it.connect_start, 0)
                        }
                        ClientMapUtil.webSocketMap[deviceNo] = myWebSocket.session?.id
                        test.message = "添加数据成功"
                        test.isSucceed = RESPONSE_SUCCEED
                    }
                }
            }
            myWebSocket.sendMessage(test)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 呼叫
     *
     * @param myWebSocket
     * @param modelBean
     */
    private fun call(myWebSocket: WebSocketServer, modelBean: ModelBean) {
        val to: String? = modelBean.callData?.toName
        val sessionTo = to?.let { ClientMapUtil[it] }
        val test = ModelBean()
        test.callData = modelBean.callData
        if (StringUtils.isEmpty(sessionTo)) {
            test.id = CALL_RESPONSE
            test.isSucceed = RESPONSE_FAILURE
            myWebSocket.sendMessage(test)
        } else {
            val socketServer = sessionTo?.let { WebSocketMapUtil[it] }
            if (socketServer != null) {
//                BeanUtils.copyProperties(modelBean, test)
                test.id = INCALL
                socketServer.sendMessage(test)
                saveMessage(modelBean.callData?.deptId, INCALL,Gson().toJson(test))
            }
        }
    }

    /**
     * 拒接接听
     */
    private fun incallResponseFailure(myWebSocket: WebSocketServer, modelBean: ModelBean) {
        try {
            val to: String? = modelBean.callData?.toName
            val sessionTo = to?.let { ClientMapUtil[it] }
            val socketServer = sessionTo?.let { WebSocketMapUtil.get(it) }
            val test = ModelBean()
            if (socketServer != null) {
                BeanUtils.copyProperties(modelBean, test)
                test.id = INCALL_RESPONSE
                test.isSucceed = RESPONSE_FAILURE
                test.callData = modelBean.callData
                socketServer.sendMessage(test)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 挂断
     */
    private fun hangUp(modelBean: ModelBean) {
        try {
            val to: String? = modelBean.callData?.toName
            val sessionTo = to?.let { ClientMapUtil[it] }
            val socketServer = sessionTo?.let { WebSocketMapUtil.get(it) }
            val test = ModelBean()
            if (socketServer != null) {
                BeanUtils.copyProperties(modelBean, test)
                test.id = HANGUP
                test.isSucceed = RESPONSE_SUCCEED
                test.callData = modelBean.callData
                socketServer.sendMessage(test)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private fun incallResponseSucceed(myWebSocket: WebSocketServer, modelBean: ModelBean) {
        try {
            val to: String? = modelBean.callData?.toName
            val sessionTo = to?.let { ClientMapUtil[it] }
            val socketServer = sessionTo?.let { WebSocketMapUtil[it] }
            val test = ModelBean()
            if (socketServer != null) {
//                BeanUtils.copyProperties(model, test)
                test.id = INCALL_RESPONSE
                test.isSucceed = RESPONSE_SUCCEED
                test.callData = modelBean.callData
                socketServer.sendMessage(test)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 发送流
     *
     * @param modelBean
     */
    private fun offer(modelBean: ModelBean) {
        try {
            val to: String? = modelBean.callData?.toName
            val sessionTo = to?.let { ClientMapUtil[it] }
            val socketServer = sessionTo?.let { WebSocketMapUtil[it] }
            socketServer?.sendMessage(modelBean)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 发送血氧数据
     *
     * @param modelBean
     */
    private fun senOxmData(myWebSocket: WebSocketServer?, modelBean: ModelBean) {
        try {
            val to: String? = modelBean.callData?.toName
            val sessionTo = to?.let { ClientMapUtil[it] }
            val socketServer = sessionTo?.let { WebSocketMapUtil[it] }
            val test = ModelBean()
            if (socketServer != null) {
                test.id = OXMDATA
                test.isSucceed = RESPONSE_SUCCEED
                test.callData = modelBean.callData
                test.oxmData = modelBean.oxmData
                socketServer.sendMessage(test)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 发送菜品订单
     *
     * @param modelBean
     */
    private fun senFoodOrderData(myWebSocket: WebSocketServer?, modelBean: ModelBean) {
        try {
            val to: String? = modelBean.callData?.toName
            val sessionTo = to?.let { ClientMapUtil[it] }
            val socketServer = sessionTo?.let { WebSocketMapUtil[it] }
            val test = ModelBean()
            if (socketServer != null) {
                test.id = FOODORDER
                test.isSucceed = RESPONSE_SUCCEED
                test.callData = modelBean.callData
                test.foodOrderList = modelBean.foodOrderList
                socketServer.sendMessage(test)
                saveMessage(modelBean.callData?.deptId, FOODORDER,Gson().toJson(test))
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 发送商城订单
     *
     * @param modelBean
     */
    private fun senProductOrderData(myWebSocket: WebSocketServer?, modelBean: ModelBean) {
        try {
            val to: String? = modelBean.callData?.toName
            val sessionTo = to?.let { ClientMapUtil[it] }
            val socketServer = sessionTo?.let { WebSocketMapUtil[it] }
            val test = ModelBean()
            if (socketServer != null) {
                test.id = PRODUCTORDER
                test.isSucceed = RESPONSE_SUCCEED
                test.callData = modelBean.callData
                test.productOrderList = modelBean.productOrderList
                saveMessage(modelBean.callData?.deptId, PRODUCTORDER,Gson().toJson(test))
                socketServer.sendMessage(test)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * ice交互
     *
     * @param modelBean
     */
    private fun candidate(modelBean: ModelBean) {
        val to: String? = modelBean.callData?.toName
        val sessinTo = to?.let { ClientMapUtil[it] }
        if (!StringUtils.isEmpty(sessinTo)) {
            val socketServer = sessinTo?.let { WebSocketMapUtil[it] }
            socketServer?.sendMessage(modelBean)
        }
    }

    fun saveMessage(deptId:Int?,  messageType: String?, message: String?) {
        webDatabase.getDataBase().insertAndGenerateKey(TBoardMessageDao) {
            set(it.messageType, messageType)
            set(it.date, DateFormatUtils.ISO_DATETIME_FORMAT.format(Date()))
            set(it.message,message)
            set(it.deptId,864)
        }
    }

}